package com.fminutes.vinciBitmap
{
	import com.fminutes.vinciBase.App;
	
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	
	/**
	 * 将矢量转为位图并将位图缓存的管理类
	 * @author lipi
	 */
	public class BitmapManager
	{
		
		//////////////////////////////////////////////////////////////////////
		//
		// 静态
		//
		/////////////////////////////////////////////////////////////////////
		
		public static const A:int = 1;
		public static const B:int = 3;
		public static const C:int = 4;
		
		/**
		 * 最低的保持的帧频，如果程序低于这个帧频draw将不进行
		 */
		public static var minFps:int = 10;
		
		/**
		 *  每次draw的时间相对于每帧运行时间的百分比
		 */
		public static var percentage:Number = 0.5;
		
		public static var appStage:Stage;
		
		
		
		private static var _instance:BitmapManager;
		
		
		/**
		 * 是否对BitmapMovieClip进行消锯齿处理
		 */
		public static var smoothing:Boolean = false;
		
		
		
		/**
		 * 取得BitmapManager实例
		 */
		private static function getInstance():BitmapManager
		{
			if(_instance == null)
			{
				_instance = new BitmapManager();
			}
			return _instance;
		}
		
		
		
		/**
		 * @param source 要进行转换的类
		 * @param compFn 完成后的回调函数
		 * @param frameCompFn 第一帧完成的回调函数
		 * @param priority 进行draw的优先级
		 * @param destroyTime 引用计数为0时延迟多长时间销毁（单位毫秒）
		 */
		public static function draw(source:Class,compFn:Function,frameCompFn:Function = null,priority:int = BitmapManager.B,destroyTime:int = 10000):void
		{
			var bitmapManager:BitmapManager = getInstance();
			bitmapManager.draw(source,compFn,frameCompFn,priority,destroyTime);
		}
		
		/**
		 * 销毁一个位图(内部将引用计数减一)
		 * @param source
		 */
		public static function destroy(source:*):void
		{
			var bitmapManager:BitmapManager = getInstance();
			bitmapManager.destroy(source);
		}
		
		//////////////////////////////////////////////////////////////////////
		//
		// 实例
		//
		/////////////////////////////////////////////////////////////////////
		
		
		public function BitmapManager()
		{
			appStage = App.appStage;
			limitTime = 1000/minFps;
			drawTime = 1000/appStage.frameRate*percentage;
			_frameTime = getTimer();
			
			_compDic = new Dictionary();
			_referenceCount = new Dictionary();
			_destroyTimeDic = new Dictionary();
			_destroyGettimeDic = new Dictionary();
			_compFnDic = new Dictionary();
			_frameCompFnDic = new Dictionary();
			_sourceMCDic = new Dictionary();
			_frameCompDic = new Dictionary();
			_frameNumDic = new Dictionary();
			
			_ing1 = [];
			_ing2 = [];
			_ing3 = [];
			_ing4 = [];
			_ing1_1 = [];
			_ing2_1 = [];
			_ing3_1 = [];
			_ing4_1 = [];
			
			_ING = [_ing1,_ing2,_ing3,_ing4,_ing1_1,_ing2_1,_ing3_1,_ing4_1];
			
			appStage.addEventListener(Event.ENTER_FRAME,enterFrameHandler);
		}
		
		//每帧运行的时间超过这个值draw将不运行
		private var limitTime:int = 100;
		
		//退出一次draw所用的时间
		private var drawTime:int = 20;
		
		
		//已完成的位图列表
		private var _compDic:Dictionary;
		
		//位图的引用计数
		private var _referenceCount:Dictionary;
		
		//销毁延迟列表
		private var _destroyTimeDic:Dictionary;
		
		//引用计数为的时间
		private var _destroyGettimeDic:Dictionary;
		
		//全部完成的回调函数列表
		private var _compFnDic:Dictionary;
		
		//完成第一帧回调函数列表
		private var _frameCompFnDic:Dictionary;
		
		//要进行draw的MovieClip
		private var _sourceMCDic:Dictionary;
		
		//第一帧已完成列表
		private var _frameCompDic:Dictionary;
		
		//movieclip帧数字典
		private var _frameNumDic:Dictionary;
		
		//偏移量
//		private var _mcOffsetDic:Dictionary;
		
		
		//当前进行中的各优先级列表
		private var _ing1:Array;
		private var _ing1_1:Array
		private var _ing2:Array;
		private var _ing2_1:Array;
		private var _ing3:Array;
		private var _ing3_1:Array;
		private var _ing4:Array;
		private var _ing4_1:Array;
		
		//所有进行中列表		
		private var _ING:Array;
		
		//上一次执行时的时间
		private var _frameTime:int = 0;
		
		//是否需要进行draw
		private var _drawEnding:Boolean = true;
		
		//进入帧的时间
		private var _enterFrameTime:int = 0;
		
		//draw是否已超时
		private var _drawOver:Boolean = false;
		
		private function enterFrameHandler(e:Event):void
		{
			drawHandler();
			destroyHandler();
		}
		
		
		/**
		 * 进行draw处理
		 */
		private function drawHandler():void
		{
			if(_drawEnding) return;
			_enterFrameTime = getTimer();
			var cFrameSpace:int = _enterFrameTime - _frameTime;
			_frameTime = _enterFrameTime;
			
			if(cFrameSpace > limitTime) return;//如果当前帧运行时间大于最高帧执行时间则直接跳出
			
			_drawOver = false;
			
//			var t:int = getTimer();
			frameHandler(_ing1,_ing1_1);
			frameHandler(_ing2,_ing2_1);
			frameHandler(_ing3,_ing3_1);
			frameHandler(_ing4,_ing4_1);
			allHandler(_ing1_1);
			allHandler(_ing2_1);
			allHandler(_ing3_1);
			allHandler(_ing4_1);
			_drawEnding = clearNullForArrar(_ING);
//			trace(getTimer() - t,"===============================");
		}
		
		
		/**
		 * 进行回收处理
		 */
		private function destroyHandler():void
		{
			var $currentTime:int = getTimer();
			for(var key:* in _referenceCount)
			{
				if(_referenceCount[key] <= 0)
				{
					var $destroyGettime:int = _destroyGettimeDic[key];
					var $destroyTime:int = _destroyTimeDic[key];
					if($currentTime - $destroyGettime > $destroyTime)
					{
						if(_compDic[key] != null)
						{
							var $compArray:Array = _compDic[key];
							for(var i:int = 0;i<$compArray.length;i++)
							{
								($compArray[i][0] as BitmapData).dispose();
							}
							
							delete _compDic[key];
							delete _referenceCount[key];
							delete _destroyTimeDic[key];
							delete _destroyGettimeDic[key];
							delete _sourceMCDic[key];
							delete _frameCompDic[key];
						}
						
					}//if
				}//if
			}//for
		}
		
		
		
		
		//第一帧帧处理器
		private function frameHandler(arr1:Array,arr2:Array):void
		{
			if(_drawOver) return;//如果draw已超时则跳出
			
			var count:int = arr1.length;
			for(var i:int = 0;i<count;i++)
			{
				var $source:* = arr1[i];
				if($source == null) continue;
				
				var $displayObject:DisplayObject = _sourceMCDic[$source] as DisplayObject;
				if($displayObject == null)
				{
					arr1[i] = null;
					continue;
				}
				
				if(_frameCompDic[$source] == null) _frameCompDic[$source] = [];
				
				var bitmapData:BitmapData
				var bitmapAndPoint:Array;
				var $totalFrames:int = 0;
				if($displayObject is MovieClip)
				{
					var $mc:MovieClip = ($displayObject as MovieClip);
					bitmapAndPoint = drawMovieClip($mc);
					$totalFrames = $mc.totalFrames;//记录帧数
					$mc.nextFrame();
				}else{
					bitmapAndPoint = drawMovieClip($displayObject);
					$totalFrames = 1;//记录帧数
				}
				
				_frameNumDic[$source] = $totalFrames;
				_frameCompDic[$source].push(bitmapAndPoint);
				
				
				callFn(_frameCompFnDic[$source],_frameCompDic[$source],_frameNumDic[$source]);
				delete _frameCompFnDic[$source];
				
				arr2.push(arr1[i]);
				arr1[i] = null;
				
				if(getTimer() - _enterFrameTime > drawTime)
				{
					_drawOver = true;
					return;
				}
			}
		}
		
		//其它帧处理器
		private function allHandler(arr:Array):void
		{
			if(_drawOver)
			{
				return;//如果draw已超时则跳出
			}
			
			var count:int = arr.length;
			for(var i:int = 0;i<count;i++)
			{
				var $source:* = arr[i];
				if($source == null) continue;
				
				var $displayObject:DisplayObject = _sourceMCDic[$source] as DisplayObject;
				if($displayObject == null)
				{
					arr[i] = null;
					continue;
				}
				
				if($displayObject is MovieClip && ($displayObject as MovieClip).totalFrames > 1)
				{//如果是MovieClip，则将它每一帧进行绘制
					var $mc:MovieClip = ($displayObject as MovieClip);
					var currentFrames:int = $mc.currentFrame;
					var total:int = $mc.totalFrames;
					for(var j:int = currentFrames;j<=total;j++)
					{
						_frameCompDic[$source].push(drawMovieClip($mc));
						$mc.nextFrame();
						
						if(getTimer() - _enterFrameTime > drawTime && j != total)//如果当前已经是最后一帧就忽略而不判断
						{
							_drawOver = true;
							return;//如果draw超时则跳出
						}
					}
				}
				
				
				_compDic[$source] = _frameCompDic[$source];
				callFn(_compFnDic[$source],_compDic[$source],_frameNumDic[$source]);
				delete _compFnDic[$source];
				delete _sourceMCDic[$source];
				arr[i] = null;
				
				if(getTimer() - _enterFrameTime > drawTime)
				{
					_drawOver = true;
					return;
				}
			}
		}
		
		
		
		
		
		
		/**
		 * draw出bitmapdata
		 * @param displayObject 需要draw的对象
		 * @return bitmapdata的列表
		 */
		private function drawMovieClip(displayObject:DisplayObject):Array
		{
			var rect:Rectangle = displayObject.getBounds(displayObject);
			rect.width = rect.width?rect.width:1;
			rect.height = rect.height?rect.height:1;
			var bitmapData:BitmapData = new BitmapData(rect.width,rect.height,true,0x00FFFFFF);
			bitmapData.draw(displayObject,new Matrix(1,0,0,1,-Math.floor(rect.x),-Math.floor(rect.y)));
			return [bitmapData,new Point(Math.floor(rect.x),Math.floor(rect.y))];
		}
		
		
		
		
		//将数组中置为null的移除
		private function clearNullForArrar(aArr:Array):Boolean
		{
			var $length:int = aArr.length;
			var i:int = 0;
			var arrisnull:Boolean = true;
			for(i = 0;i<$length;i++)
			{
				var cArr:Array = aArr[i] as Array;
				deleteArrayItemForValue(cArr,null);
				if(cArr.length > 0) arrisnull = false;
			}
			return arrisnull;
		}
		
		private function deleteArrayItemForValue(aArray:Array,value:Object):Array
		{
			var count:int = aArray.length;
			var index:int = 0;
			var item:Object;
			for(var i:int = 0;i<count;i++)
			{
				if(aArray[i] != value)
				{
					item = aArray[index];
					aArray[index] = aArray[i];
					aArray[i] = item;
					index += 1;
				}
			}
			aArray.length = index;
			return aArray;
		}
		
		//调用回调函数
		private function callFn(fnList:Array,data:Object,totalFrames:Object):void
		{
			if(fnList == null) return;
			
			var fnListLength:int = fnList.length;
			for(var i:int = 0;i<fnListLength;i++)
			{
				var fn:Function = fnList[i] as Function;
				if(fn != null)
				{
					fn(data,totalFrames);
				}
			}
		}
		
		
		/**
		 * @param source 要进行转换的类
		 * @param compFn 完成后的回调函数
		 * @param frameCompFn 第一帧完成的回调函数
		 * @param priority 进行draw的优先级
		 * @param destroyTime 引用计数为0时延迟多长时间销毁（单位毫秒）
		 */
		private function draw(source:Class,compFn:Function,frameCompFn:Function = null,priority:int = BitmapManager.B,destroyTime:int = 1000):void
		{
			if(_compDic[source] != null)
			{//如果当前要取得的类已经完成则将引用计数加1然后直接调用回调函数
				compFn(_frameCompDic[source],_frameNumDic[source]);
				if(frameCompFn != null)
				{
					frameCompFn(_frameCompDic[source],_frameNumDic[source]);
				}
				if(_referenceCount[source] == null) _referenceCount[source] = 0;
				_referenceCount[source] = _referenceCount[source] + 1;
				
			}else{
				if(frameCompFn != null)
				{
					if(_frameCompDic[source] != null)
					{//如果第一帧已完成调用回调函数
						frameCompFn(_frameCompDic[source],_frameNumDic[source]);
					}
					else
					{
						//注册完成第一帧的回调函数
						if(_frameCompFnDic[source] == null) _frameCompFnDic[source] = [];
						(_frameCompFnDic[source] as Array).push(frameCompFn);
					}
				}
				
				//注册全部完成的回调函数
				if(_compFnDic[source] == null) _compFnDic[source] = [];
				(_compFnDic[source] as Array).push(compFn);
				
				_destroyTimeDic[source] = destroyTime;
				
				if(_sourceMCDic[source] == null)
				{//如果要draw的实例不存在则实例化一个
					var $object:Object = new source();
					if($object is MovieClip) ($object as MovieClip).stop();
					_sourceMCDic[source] = $object;
				
					//注册到优先级
					switch(priority)
					{
						case BitmapManager.A:
							_ing1.push(source);
							break;
						case BitmapManager.B:
							if(_frameCompDic[source] == null)
							{
								_ing2.push(source);
							}else{
								_ing3.push(source);
							}
							break;
						case BitmapManager.C:
							_ing4.push(source);
							break;
					}
				}
				
				_drawEnding = false;
				
				if(_referenceCount[source] == null) _referenceCount[source] = 0;
				_referenceCount[source] = _referenceCount[source] + 1;
			}
		}
		
		
		private function destroy(source:*):void
		{
			if(_referenceCount[source] > 1)
			{
				_referenceCount[source] = _referenceCount[source] - 1;
			}else if(_referenceCount[source] == 1){
				_referenceCount[source] = _referenceCount[source] - 1;
				_destroyGettimeDic[source] = getTimer();
			}
		}
		
		
	}
}
